import { Matrix4 } from "../../utils/Matrix4";
import { Primitives } from "../../utils/Primitives";
import { TextrueUtil } from "../../utils/TextureUtil";
import { Util } from "../../utils/Util";
import { WebGLUtil } from "../../utils/WebGLUtil";
import { Render } from "../Render";
import { WebglTemplateBase } from "../template/WebglTemplateBase";

/*
 * @Author: Snow
 * @Date: 2021-10-11 20:35:00
 * @Description: 3D纹理 
 */
export class TextureCubeMap extends WebglTemplateBase {
    protected override initProgram(): void {
        this.vsSource = `
            attribute vec4 a_position;
            
            uniform mat4 u_matrix;
            
            varying vec3 v_normal;
            
            void main() {
                // Multiply the position by the matrix.
                gl_Position = u_matrix * a_position;
                
                v_normal = normalize(a_position.xyz);
            }
        `;

        this.fsSource = `
            precision mediump float;

            // 从顶点着色器传入。
            varying vec3 v_normal;
            
            // 纹理。
            uniform samplerCube u_texture;
            
            void main() {
                gl_FragColor = textureCube(u_texture, normalize(v_normal));
            }
        `;
        super.initProgram();
    }

    protected override initBuffers(): void {
        super.initBuffers();
        const gl = Render.GL;

        var positions = [
            -0.5, -0.5, -0.5,
            -0.5, 0.5, -0.5,
            0.5, -0.5, -0.5,
            -0.5, 0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, -0.5, -0.5,

            -0.5, -0.5, 0.5,
            0.5, -0.5, 0.5,
            -0.5, 0.5, 0.5,
            -0.5, 0.5, 0.5,
            0.5, -0.5, 0.5,
            0.5, 0.5, 0.5,

            -0.5, 0.5, -0.5,
            -0.5, 0.5, 0.5,
            0.5, 0.5, -0.5,
            -0.5, 0.5, 0.5,
            0.5, 0.5, 0.5,
            0.5, 0.5, -0.5,

            -0.5, -0.5, -0.5,
            0.5, -0.5, -0.5,
            -0.5, -0.5, 0.5,
            -0.5, -0.5, 0.5,
            0.5, -0.5, -0.5,
            0.5, -0.5, 0.5,

            -0.5, -0.5, -0.5,
            -0.5, -0.5, 0.5,
            -0.5, 0.5, -0.5,
            -0.5, -0.5, 0.5,
            -0.5, 0.5, 0.5,
            -0.5, 0.5, -0.5,

            0.5, -0.5, -0.5,
            0.5, 0.5, -0.5,
            0.5, -0.5, 0.5,
            0.5, -0.5, 0.5,
            0.5, 0.5, -0.5,
            0.5, 0.5, 0.5,

        ];

        let posBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER,posBuffer);
        gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(positions),gl.STATIC_DRAW);

        let posLocation =  gl.getAttribLocation(this.programInfo.program,"a_position");
        gl.enableVertexAttribArray(posLocation);
        gl.vertexAttribPointer(posLocation,3,gl.FLOAT,false,0,0);

        // Create a texture.
        let textureCubeMap = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_CUBE_MAP, textureCubeMap);

        // 获取二维上下文
        /** @type {Canvas2DRenderingContext} */
        const ctx = document.createElement("canvas").getContext("2d");

        ctx.canvas.width = 128;
        ctx.canvas.height = 128;

        const faceInfos = [
            { target: gl.TEXTURE_CUBE_MAP_POSITIVE_X, faceColor: '#F00', textColor: '#0FF', text: '+X' },
            { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X, faceColor: '#FF0', textColor: '#00F', text: '-X' },
            { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y, faceColor: '#0F0', textColor: '#F0F', text: '+Y' },
            { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, faceColor: '#0FF', textColor: '#F00', text: '-Y' },
            { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z, faceColor: '#00F', textColor: '#FF0', text: '+Z' },
            { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, faceColor: '#F0F', textColor: '#0F0', text: '-Z' },
          ];
        faceInfos.forEach((faceInfo) => {
            const {target, faceColor, textColor, text } = faceInfo;
            this.generateFace(ctx, faceColor, textColor, text);

            // 上传画布到立方体贴图的每个面。
            const level = 0;
            const internalFormat = gl.RGBA;
            const format = gl.RGBA;
            const type = gl.UNSIGNED_BYTE;
            gl.texImage2D(target, level, internalFormat, format, type, ctx.canvas);
            // 展示结果
            ctx.canvas.toBlob((blob) => {
                const img = new Image();
                img.src = URL.createObjectURL(blob);
                document.body.appendChild(img);
            });
        });

        



        if (Util.isPowerOf2(ctx.canvas.width) && Util.isPowerOf2(ctx.canvas.width)) {
            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
        } else {
            // 不是 2 的幂，关闭贴图并设置包裹模式为到边缘
            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        }

      
        
        let cameraAngleRadians = Util.degToRad(0);
        let fieldOfViewRadians = Util.degToRad(60);
        let cameraHeight = 50;

        let drawScene = () => {
           
            let time = this.ts;
            time = time;
            WebGLUtil.resizeCanvasToMatchDisplaySize(gl);
            // Clear the canvas AND the depth buffer.
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);


            gl.useProgram(this.programInfo.program);

            let texUnforms = gl.getUniformLocation(this.programInfo.program,"u_texture");
            gl.uniform1i(texUnforms,0);
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_CUBE_MAP,textureCubeMap);

            // Compute the projection matrix
            let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            var projectionMatrix = Matrix4.perspective(fieldOfViewRadians, aspect, 1, 2000);

            // Compute the camera's matrix using look at.
            let cameraPosition = [0, 0, 2];
            let target = [0, 0, 0];
            let up = [0, 1, 0];
            let cameraMatrix = Matrix4.lookAt(cameraPosition, target, up);

            // Make a view matrix from the camera matrix.
            let viewMatrix = Matrix4.invert(cameraMatrix);

            let viewProjectionMatrix = Matrix4.multiply(projectionMatrix, viewMatrix);

         
            let cubeXRotation = -time;
            let cubeYRotation = time;
            
            let mat1 = Matrix4.rotateX(cubeXRotation);
            let mat2 = Matrix4.rotateY(cubeYRotation);
            
            let matrix = Matrix4.multiply(viewProjectionMatrix,mat1);
            matrix = Matrix4.multiply(matrix,mat2);

            let matrixLocation = gl.getUniformLocation(this.programInfo.program,"u_matrix")
            gl.uniformMatrix4fv(matrixLocation,false, new Float32Array(matrix));

            gl.drawArrays(gl.TRIANGLES,0,6 * 6);
        }
        this.draw = drawScene;
    }

    private generateFace(ctx: CanvasRenderingContext2D, faceColor: string, textColor: string, text: string): void {
        const { width, height } = ctx.canvas;
        ctx.fillStyle = faceColor;
        ctx.fillRect(0, 0, width, height);
        ctx.font = `${width * 0.7}px sans-serif`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillStyle = textColor;
        ctx.fillText(text, width / 2, height / 2);
    }
}